#include "buffer.h"
#include "../Log/log.h"


Buffer::Buffer(int initBuffSize) : buffer_(initBuffSize), readPos_(0), writePos_(0) {}

char * Buffer::BeginPtr_()
{
    // 意思就是先对迭代器解引用得到第一个字符
    // 再取地址得到首地址
    return &*buffer_.begin();
}
const char* Buffer::BeginPtr_() const {
    return &*buffer_.begin();
}

void Buffer::MakeSpace_(size_t len) {
    // 空间不够用了
    if(WritableBytes() + PrependableBytes() < len) {
        // 因为 writePos_ >= readPos_ 所以这么做就只是延伸了一些
        // 会自动拷贝原始数据过去的
        buffer_.resize(writePos_ + len + 1);
    } else {
        // 虽然够用 但是问题是不连续 不连续也不好用

        // 这么多数据需要拷贝
        size_t readable = ReadableBytes();
        // 拷贝到头部
        std::copy(BeginPtr_() + readPos_, BeginPtr_() + writePos_, BeginPtr_());
        readPos_ = 0;
        writePos_ = readPos_ + readable;
        assert(readable == ReadableBytes());
    }
}

// const 成员函数内部不能修改对象的非静态成员变量
size_t Buffer::ReadableBytes() const {
    return writePos_ - readPos_;
}

size_t Buffer::WritableBytes() const {
    return buffer_.size() - writePos_;
}

// 之前读到哪个位置了
size_t Buffer::PrependableBytes() const {
    return readPos_;
}

// 当前读指针的开始位置
//?(resize不会改变开始位置吗?)
const char* Buffer::Peek() const {
    return BeginPtr_() + readPos_;
}


void Buffer::Retrieve(size_t len) {
    assert(len <= ReadableBytes());
    readPos_ += len;
}

void Buffer::RetrieveUntil(const char * end)
{
    assert(Peek() <= end);      // 开始位置小于end
    Retrieve(end - Peek());     // 加上这么大的位置

}

void Buffer::RetrieveAll() {
    // 性能更好但是兼容性差
    bzero(&buffer_[0], buffer_.size());
    readPos_ = 0;
    writePos_ = 0; 
}

std::string Buffer::RetrieveAllToStr() {
    std::string str(Peek(), ReadableBytes());
    RetrieveAll();
    return str;
}

const char* Buffer::BeginWriteConst() const {
    return BeginPtr_() + writePos_;
}

char* Buffer::BeginWrite() {
    return BeginPtr_() + writePos_;
}

void Buffer::HasWritten(size_t len) {
    writePos_ += len;
} 
/* 说白了就是重载了一下 支持多个输入格式 */
void Buffer::Append(const std::string& str) {

    Append(str.data(), str.length());
}

void Buffer::Append(const void* data, size_t len) {
    assert(data);
    /* static_cast : 低风险转换的意思 */
    Append(static_cast<const char*>(data), len);
}

/*最终都是调用这个函数 首先要确定可读 */
void Buffer::Append(const char* str, size_t len) {
    assert(str);
    EnsureWriteable(len);
    // 把 str->str + len的数据写入到这里
    std::copy(str, str + len, BeginWrite());
    HasWritten(len);
}

void Buffer::Append(const Buffer& buff) {
    Append(buff.Peek(), buff.ReadableBytes());
}
/*对当前Buffer进行扩容操作*/
void Buffer::EnsureWriteable(size_t len) {
    if(WritableBytes() < len) {
        MakeSpace_(len);
    }
    assert(WritableBytes() >= len);
}

/*读数据(真的不会爆栈嘛)*/
ssize_t Buffer::ReadFd(int fd, int * saveErrno) {
    // Linux默认栈的大小是8MB 也就是8*1024*1024这么大
    char buff[65535];
    struct iovec iov[2];
    const size_t writable = WritableBytes();
    iov[0].iov_base = BeginPtr_() + writePos_;
    iov[0].iov_len = writable;
    // 因为你也不确定数据能够读完
    iov[1].iov_base = buff;
    iov[1].iov_len = sizeof(buff);

    // 这是一个尽量读的操作 只要不超过局限都进行读
    const ssize_t len = readv(fd, iov, 2);
    //LOG_INFO("Buffer read len : [%d]",len);
    if(len < 0) {
        *saveErrno = errno;
    // 空间够用
    } else if(static_cast<size_t>(len) <= writable) {
        writePos_ += len;
    // 需要额外的把空间了 或者重新操作一下
    } else {
        writePos_ = buffer_.size();
        Append(buff, len - writable);
    }
    return len;
}

ssize_t Buffer :: WriteFd(int fd, int * saveErrno) {
    size_t readSize = ReadableBytes();
    ssize_t len = write(fd, Peek(), readSize);
    if(len < 0) {
        *saveErrno = errno;
        return len;
    } 
    readPos_ += len;
    return len;
}